#pragma once

#include "../comm/net.hpp"
#include "../comm/message.hpp"
#include <thread>
#include "../comm/dispatch.hpp"
#include "requestor.hpp"
#include "rpc_caller.hpp"
#include "rpc_registry.hpp"
#include "rpc_topic.hpp"

namespace Client
{
    using namespace Dispatch;
    class RegistryClient
    {
    public:
        using ptr = shared_ptr<RegistryClient>;
        // 构造函数传入注册中心的地址信息，用于连接注册中心
        RegistryClient(const string &ip, int port)
            : _requestor(make_shared<Requestor>()),
              _providerer(make_shared<Provider>(_requestor)),
              _dispatcher(make_shared<Dispatcher>())
        {
            auto rsp_cb = std::bind(&Client::Requestor::OnResponse, _requestor.get(),
                                    placeholders::_1, placeholders::_2);

            _dispatcher->RegisterHander<BaseMessage>(Mtype::RSP_SERVICE, rsp_cb); // 注册映射关系

            auto message_cb = std::bind(&Dispatch::Dispatcher::OnMessage, _dispatcher.get(),
                                        placeholders::_1, placeholders::_2);
            _client = ClientFactory::create(ip, port);

            _client->SetMessageCB(message_cb);
            _client->Connect();
        }
        // 向外提供服务注册接口
        bool RegistryMethod(const string &method, const Address &host)
        {
            return _providerer->RegistryMethod(_client->Conncection(), method, host);
        }

    private:
        Requestor::ptr _requestor;
        Client::Provider::ptr _providerer;
        Dispatcher::ptr _dispatcher;
        BaseClient::ptr _client;
    };

    class DiscoveryClient
    {
    public:
        using ptr = shared_ptr<DiscoveryClient>;
        // 构造函数传入注册中心的地址信息，用于连接注册中心
        DiscoveryClient(const string &ip, int port, const Discoverer::offline_cb &cb)
            : _requestor(make_shared<Requestor>()),
              _discoverer(make_shared<Client::Discoverer>(_requestor, cb)),
              _dispatcher(make_shared<Dispatcher>())
        {
            auto rsp_cb = std::bind(&Client::Requestor::OnResponse, _requestor.get(),
                                    placeholders::_1, placeholders::_2);

            _dispatcher->RegisterHander<BaseMessage>(Mtype::RSP_SERVICE, rsp_cb); // 注册映射关系

            auto req_cb = std::bind(&Client::Discoverer::OnServiceRequest, _discoverer.get(),
                                    placeholders::_1, placeholders::_2);
            _dispatcher->RegisterHander<ServiceRequest>(Mtype::REQ_SERVICE, req_cb); // 注册映射关系

            auto message_cb = std::bind(&Dispatch::Dispatcher::OnMessage, _dispatcher.get(),
                                        placeholders::_1, placeholders::_2);
            _client = ClientFactory::create(ip, port);
            _client->SetMessageCB(message_cb);
            _client->Connect();
        }
        // 向外提供服务发现接口
        bool ServiceDiscovery(const string &method, Address &host)
        {
            return _discoverer->ServiceDiscovery(_client->Conncection(), method, host);
        }

    private:
        Requestor::ptr _requestor;
        Client::Discoverer::ptr _discoverer;
        Dispatcher::ptr _dispatcher;
        BaseClient::ptr _client;
    };

    class RpcClient
    {
    public:
        using ptr = shared_ptr<RpcClient>;
        // 构造函数--用于是否启用服务发现功能，也决定了传入的地址信息是注册中心的地址，还是服务提供者的地址
        RpcClient(bool enabelDiscovery, const string &ip, int port)
            : _enabeldiscovery(enabelDiscovery), _requestor(make_shared<Requestor>()),
              _dispatcher(make_shared<Dispatcher>()), _caller(make_shared<RpcCaller>(_requestor))
        {
            auto rsp_cb = std::bind(&Client::Requestor::OnResponse, _requestor.get(),
                                    placeholders::_1, placeholders::_2);

            _dispatcher->RegisterHander<BaseMessage>(Mtype::RSP_RPC, rsp_cb); // 注册映射关系
            // 如果启用了服务发现，地址信息是注册中心地址，是服务发现客服端链接地址，通过地址实例化discovery_client
            // 如果没有启用服务发现，则地址信息是服务提供者地址，则直接实例化rpc_client
            if (_enabeldiscovery)
            {
                auto off_cb = bind(&RpcClient::DelClient, this, placeholders::_1);
                _discovery_client = make_shared<DiscoveryClient>(ip, port, off_cb);
            }
            else
            {
                auto message_cb = std::bind(&Dispatch::Dispatcher::OnMessage, _dispatcher.get(),
                                            placeholders::_1, placeholders::_2);
                _rpc_client = ClientFactory::create(ip, port);
                _rpc_client->SetMessageCB(message_cb);
                _rpc_client->Connect();
            }
        }
        // 向外提供服务注册接口
        bool Call(const string &method, const Json::Value &params, Json::Value &result)
        {
            // 获取服务提供者：1.服务发现，2.固定服务提供者
            BaseClient::ptr client = GetClient(method);
            if (client.get() == nullptr)
            {
                return false;
            }
            // 3.通过客户端连接，发送rpc请求
            return _caller->Call(client->Conncection(), method, params, result);
        }
        bool Call(const string &method, const Json::Value &params, RpcCaller::JsonAsyncResponse &result)
        {
            // 获取服务提供者：1.服务发现，2.固定服务提供者
            BaseClient::ptr client = GetClient(method);
            if (client.get() == nullptr)
            {
                return false;
            }
            // 3.通过客户端连接，发送rpc请求
            return _caller->Call(client->Conncection(), method, params, result);
        }
        bool Call(const string &method, const Json::Value &params, const RpcCaller::JsonResponseCallBack &result)
        {
            // 获取服务提供者：1.服务发现，2.固定服务提供者
            BaseClient::ptr client = GetClient(method);
            if (client.get() == nullptr)
            {
                return false;
            }
            // 3.通过客户端连接，发送rpc请求
            return _caller->Call(client->Conncection(), method, params, result);
        }

    private:
        BaseClient::ptr NewClient(const Address &host)
        {
            auto message_cb = std::bind(&Dispatch::Dispatcher::OnMessage, _dispatcher.get(),
                                        placeholders::_1, placeholders::_2);
            auto client = ClientFactory::create(host.first, host.second);
            client->SetMessageCB(message_cb);
            client->Connect();
            PutClient(host, client);
            return client;
        }
        BaseClient::ptr GetClient(const Address &host)
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _rpc_clients.find(host);
            if (it == _rpc_clients.end())
            {
                return BaseClient::ptr();
            }
            return it->second;
        }
        BaseClient::ptr GetClient(const string &method) //&
        {
            BaseClient::ptr client;
            if (_enabeldiscovery)
            {
                // 1.服务发现，获取地址信息
                Address host;
                bool ret = _discovery_client->ServiceDiscovery(method, host);
                if (ret == false)
                {
                    ELog("当前%s服务，没有找到服务提供者", method.c_str());
                    return BaseClient::ptr();
                }
                // 2.查看服务提供者受否实例化客服端，没有则创建
                client = GetClient(host);
                if (client.get() == nullptr)
                {
                    client = NewClient(host);
                }
            }

            else
            {
                client = _rpc_client;
            }
            return client;
        }
        void PutClient(const Address &host, const BaseClient::ptr &client)
        {
            unique_lock<mutex> lock(_mutex);
            _rpc_clients.insert(make_pair(host, client));
        }
        void DelClient(const Address &host)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _rpc_clients.erase(host);
        }

    private:
        struct AddressHash
        {
            size_t operator()(const Address &host) const
            {
                string addr = host.first + to_string(host.second);
                return hash<string>{}(addr);
            }
        };

        bool _enabeldiscovery;
        DiscoveryClient::ptr _discovery_client;
        Requestor::ptr _requestor;
        Dispatcher::ptr _dispatcher;
        RpcCaller::ptr _caller;
        std::mutex _mutex;
        BaseClient::ptr _rpc_client;
        // 使用长连接----->[host,[client1,client2,....]]---效率高
        unordered_map<Address, BaseClient::ptr, AddressHash> _rpc_clients; // 用于客服端发现的客户端连接池
    };

    class TopicClient
    {
    public:
        using ptr = shared_ptr<TopicClient>;
        TopicClient(const string &ip, int port)
            : _requestor(make_shared<Requestor>()),
              _dispatcher(make_shared<Dispatcher>()),
              _topic_manger(make_shared<Client::TopicManger>(_requestor))
        {
            auto rsp_cb = std::bind(&Requestor::OnResponse, _requestor.get(),
                                    placeholders::_1, placeholders::_2);

            _dispatcher->RegisterHander<BaseMessage>(Mtype::RSP_TOPIC, rsp_cb); // 注册映射关系

            auto msg_cb = bind(&TopicManger::OnPublish, _topic_manger.get(),
                               placeholders::_1, placeholders::_2);
            _dispatcher->RegisterHander<TopicRequest>(Mtype::REQ_TOPIC, msg_cb); // 注册映射关系

            auto message_cb = std::bind(&Dispatch::Dispatcher::OnMessage, _dispatcher.get(),
                                        placeholders::_1, placeholders::_2);
            _rpc_client = ClientFactory::create(ip, port);
            _rpc_client->SetMessageCB(message_cb);
            _rpc_client->Connect();
        }
        bool Create(const string &key)
        {
            return _topic_manger->Create(_rpc_client->Conncection(), key);
        }
        bool Remove(const string &key)
        {
            return _topic_manger->Remove(_rpc_client->Conncection(), key);
        }
        // 订阅功能--处理
        bool Subscribe(const string &key, const TopicManger::SubCallback &cb)
        {
            return _topic_manger->Subscribe(_rpc_client->Conncection(), key,cb);
        }

        bool Cancel(const string &key)
        {
            return _topic_manger->Cancel(_rpc_client->Conncection(), key);
        }
        bool Publish(const string &key, const string &msg)
        {
            return _topic_manger->Publish(_rpc_client->Conncection(), key, msg);
        }
        void Shutdown() {
             _rpc_client->Shutdown();
        }
    private:
        Requestor::ptr _requestor;
        Dispatcher::ptr _dispatcher;
        TopicManger::ptr _topic_manger;
        BaseClient::ptr _rpc_client;
    };
}